function mock(funName) {
	return new Mock(funName);
}

/*
 * Mock
 */
function Mock(funName) {	
	this.funName = funName;		// String
	this.origFun = null;			// Function
	this.mockFun = null; 			// Function
  
  this.__declareIfNotDefine__(funName);
	eval(remainInvokeTimes(funName) + ' = 1;');
}

Mock.prototype.__declareIfNotDefine__ = function(funName) {
	eval("this.undefinedFun = typeof " + funName + " == 'undefined';");
	if (this.undefinedFun) eval(funName + '= null;');
}

Mock.prototype.thenReturn = function() {
	var returnValues = arguments;
	var counter = 0;
	eval(remainInvokeTimes(this.funName) + ' = ' + arguments.length + ';');
	var remainInvokeTimesString = remainInvokeTimes(this.funName);
		
	this.mockFun = function() {	
		eval(remainInvokeTimesString + '--;');
		return returnValues[counter++]; 
	};	

	eval('this.origFun = ' + this.funName + ';');
	eval(this.funName + ' = this.mockFun;');
	return this;
}

Mock.prototype.expect = function(times) {
	var remainInvokeTimesString = remainInvokeTimes(this.funName);
	eval(remainInvokeTimesString + ' = ' + times + ';');
	this.mockFun = function() {	
		eval(remainInvokeTimesString + '--;');
	};
	eval('this.origFun = ' + this.funName + ';');
	eval(this.funName + ' = this.mockFun;');
	return this;
} 

Mock.prototype.renew = function() {
	eval(this.funName + ' =  this.origFun;');
	eval('delete ' + remainInvokeTimes(this.funName));
	if (this.undefinedFun) {
		eval('delete ' + this.funName);	
	}
  return this;
}

Mock.prototype.verify = function() {
	eval('if (' + remainInvokeTimes(this.funName) + " != 0) { throw new ExpectationError(''); }"); 
	return this;
}

function remainInvokeTimes(funName) {
	return funName + "RemainInvokedTimes";
}

/*
 * ExpectationError
 */
function ExpectationError(message) {
	this.message = message;	
}
ExpectationError.prototype.name = 'ExpectationError';
